const p = require("path");
// chalk插件，用来在命令行中输入不同颜色的文字
const chalk = require("chalk");
const webpack = require("webpack");
const recursiveRead = require("./readdir.js");
const VirtualModulePlugin = require("./virtual-module.js");

let directory = __dirname;
let folder = false;
let allScoped = false;
let createdFiles = [];

class VueBuilderPlugin {
	constructor(options) {
		if (p.isAbsolute(options.path)) {
			directory = options.path;
		} else {
			directory = p.resolve(p.join(__dirname, "..", "..", options.path || ""));
		}
		if (options.folder) {
			folder = true;
		}
		if (options.allScoped) {
			allScoped = true;
		}
	}
}

const buildVues = (compiler, callback) => {
	// eslint-disable-next-line no-console
	console.log(chalk.cyan("\n- Building vue files ..."));
	recursiveRead(directory, (err, files) => {
			if (err) {
				return callback(err);
			}
			const vues = {};
			const sources = {
				script: {},
				template: {},
				style: {}
			};
			const langCheck = (file, extension, type) => {
				const length = -5 - extension.length;
				let scoped = false;
				if (file.slice(length) === `.vue.${extension}`) {
					let name = file.slice(0, length);
					if (type === "style" && name.slice(-7) === ".scoped") {
						scoped = true;
						name = name.slice(0, -7);
					}
					if (type === "style" && allScoped) {
						scoped = true;
					}
					vues[name] = true;
					sources[type][name] = {
						file,
						lang: extension
					};
					if (scoped) {
						sources.style[name].scoped = true;
					}
					return true;
				}
				return false;
			};

			const singleVue = (name, dirname) => {
				let data = "";
				const script = sources.script[name];
				const style = sources.style[name];
				const template = sources.template[name];
				const relate = (file) => `.${p.sep}${p.relative(dirname, file)}`;
				if (script) {
					data += `<script src="${relate(script.file)}" lang="${script.lang}"></script>\n`;
				}
				if (style) {
					data += `<style src="${relate(style.file)}" lang="${style.lang}" ${style.scoped ? " scoped" : ""}></style>\n`;
				}
				if (template) {
					data += `<template src="${relate(template.file)}" lang="${template.lang}"></template>\n`;
				}
				return data;
			};

			const fileType = {
				"style": ["css", "sass", "scss", "less", "styl"],
				"script": ["js", "coffee", "ts"],
				"template": ["html", "jade", "pug"]
			};
			files.forEach((file) => {
				let keys = Object.keys(fileType);
				for (let key of keys) {
					let extensions = fileType[key];
					for (let extension of extensions) {
						if (langCheck(file, extension, key)) {
							return;
						}
					}
				}
			});

			Object.keys(vues).forEach((vue) => {
				let dest = vue;
				if (folder && p.basename(vue) === p.basename(p.dirname(vue))) {
					dest = p.dirname(vue);
				}
				if (sources.script[vue] || sources.style[vue] || sources.template[vue]) {
					const modulePath = `${dest}.vue`;
					const ctime = VirtualModulePlugin.statsDate();
					const contents = singleVue(vue, p.dirname(dest));
					const fs = (this && this.fileSystem) || compiler.inputFileSystem;
					const wpversion = webpack.version && webpack.version[0];

					createdFiles.push(modulePath);
					VirtualModulePlugin.populateFilesystem({
						fs, modulePath, contents, ctime, wpversion
					});
				}
			});
			if (typeof callback === "function") {
				return callback();
			}
		}
	);
};

VueBuilderPlugin.prototype.apply = (compiler) => {
	if (webpack.version && webpack.version[0] >= 4) {
		compiler.hooks.run.tap("VueBuilderPlugin", (compilation, callback) => buildVues(compiler, callback));
		compiler.hooks.watchRun.tap("VueBuilderPlugin", (compilation, callback) => buildVues(compiler, callback));

		compiler.hooks.afterCompile.tap("VueBuilderPlugin", (compilation, callback) => {
			createdFiles.forEach((file) => {
				compilation.fileDependencies.delete(file);
			});
			if (typeof callback === "function") {
				callback();
			}
		});
	} else {
		compiler.plugin("run", (compilation, callback) => buildVues(callback, compiler));
		compiler.plugin("watch-run", (compilation, callback) => buildVues(callback, compiler));

		compiler.plugin("after-compile", (compilation, callback) => {
			createdFiles.forEach((file) => {
				compilation.fileDependencies.delete(file);
			});
			if (typeof callback === "function") {
				callback();
			}
		});
	}
};

module.exports = VueBuilderPlugin;
